#pragma once

//WGLENGINE_DLL
#ifdef WGLENGINE_DLL
#define WGLENGINE_EXPORT __declspec(dllexport)
#else
#define WGLENGINE_EXPORT __declspec(dllimport)
#endif

#include "WContext.h"
#include "glm\glm.hpp"
#include "GL\glew.h"

#include "Camera.h"
#include "DirectionalLight.h"
#include "ShadowMap.h"
#include "TextureCubeMap.h"

#include <vector>
#include <memory>

/*
**Uniform params ubo: global ubo for all the objects across the application
*/
struct UniformParams {
	glm::mat4 projection;
	glm::mat4 view;
	glm::mat4 viewProjMat;
	glm::mat4 biasMat;
	glm::mat4 shadowProjection;
	glm::mat4 worldToLightMat;
	glm::vec4 camPosition;
	glm::vec4 lightDir;
};

/*
**Shader Params ubo: contains the model matrix for objects in the scene
**note: 65536 is the max kb for ubo, thus we use 1000 as the max number of
**objects in the scene. If we want more, then we have to implement with SSBO instead
*/
struct ShaderParams {
	glm::mat4 model[1000]; 
};

class WGLENGINE_EXPORT WRenderer : public WContext
{
public:
	WRenderer(bool& running);
	~WRenderer();
	
	virtual void Init();

	virtual void Run()
	{
		RenderLoop();
	}

	glm::mat4 GetProjectionMatrix()
	{
		return projectionMatrix;
	}

	glm::mat4 GetViewMatrix()
	{
		//the actual view matrix for objects (not camera matrix)

		if(mainCamera != nullptr)
		{
			return mainCamera->GetViewMatrix();
		}
		return glm::mat4(1.0f);
	}

	void SetModelMatrix(unsigned int id, glm::mat4& modelMatrix)
	{
		shaderParams.model[id] = modelMatrix;
	}
	
	enum RenderPass {NORMAL = 0, SHADOWPASS = 1};

	static const char* sharedUniformVariables[];
	static RenderPass Pass;

	static std::shared_ptr<WRenderer> renderer;

protected:
	virtual void CreateContext();
	
	virtual void PreUpdate();
	virtual void Update();

	virtual void PreRender();
	virtual void Render();
	
	void UpdateUBOForRender();
	void UpdateUBOForShadowPass();

	//handle mouse input
	virtual void PollInput();
	void PollMouseInput(sf::Event& event);

	//render loop for update and render
	void RenderLoop();
	void RenderShadow();

	//camera and light instances
	std::shared_ptr<Camera> mainCamera;
	std::shared_ptr<DirectionalLight> light;
	std::shared_ptr<ShadowMap> shadowMap;


	//window management
	//TODO: remove this from the dll library, window management
	//needs to be done at the application layer
	sf::ContextSettings* settings;
	sf::Window* window;
	
	GLuint sharedUniformBuffer;		//ubo, shared by all scene objects
	UniformParams uParams;			//view projection matrix struct for ubo

	GLuint shaderParamsID;
	ShaderParams shaderParams;
	
	glm::mat4 projectionMatrix;
	
	bool initiated;
};